import React, { Component } from 'react';
import {
  Modal,
  Tabs,
  Input,
  Radio,
  Slider,
  Button,
  message,
  Select,
  Icon,
  Spin,
  // Checkbox,
  Popover
  // Switch,
  // Tooltip
} from 'antd';
import PropTypes from 'prop-types';
import { addZoomeye, getTargetList, getAllPortTemplates } from '@api/task';
import {
  NAME_RE,
  IP_RE,
  IP_INTERVAL_RE,
  CIDR_RE,
  PORT_RE,
  PORT_RANGE_RE,
  MAX_DEEP_DETECTION_COUNT,
  MAX_FAST_DETECTION_COUNT,
  MAX_DETECTION_PORT
} from '@util/constants';
import cn from 'classnames';
import calcZoomeyeRate, { PACKETS_PER_MB } from '@util/calc-zoomeye-rate';
import getIpsCount from '@util/get-ips-count';
import EraserPng from '../../images/eraser.png';
import { get } from 'lodash';
import CheckboxSelect from '@components/checkbox-select';
import RunAtTimePicker from '@components/run-at-time-picker';
import './index.less';
import getPortsCount from '@util/get-ports-count';
import { connect } from 'react-redux';
import moment from 'moment';

const { TabPane } = Tabs;
const TextArea = Input.TextArea;
const RadioGroup = Radio.Group;

const ipsInfo = [
  '1.请输入单个或者多个资产，多个资产请换行分割,例如:',
  '10.0.1.0',
  '10.0.1.2',
  '2.输入网段格式，可以根据习惯选择下面任意格式:',
  '格式1: 192.168.1.1-192.168.255.255',
  '格式2: 192.168.1.0/24'
].join('\r\n');

const portsInfo = ['请使用"－"指定端口范围，使用 "," 分割端口。', '例如：21,22,23,10-50'].join(
  '\r\n'
);

class ZoomeyeModal extends Component {
  static defaultState = {
    currentTab: 0,
    mode: 'deep',
    ipsType: 'custom',
    portsType: 'common',
    ips: '',
    ports: '21-25,53,80,111,137,139,443,8080',
    cycle: 0,
    webFinger: false,
    ipsCount: 0,
    packets: PACKETS_PER_MB,
    packetsType: 'not-custom',
    taskName: '',
    ipsError: '',
    portsError: '',
    taskNameError: '',

    addingZoomeye: false,
    ipRangesModalVisible: false,
    ipRangeSearch: '',
    selectedIpRanges: [],
    selectedPortTemplate: '',
    runAt: {
      isRunAt: false,
      time: moment().format('YYYY-MM-DD HH:mm')
    },
    urgent: false
  };
  constructor(props) {
    super(props);
    const ips = Array.isArray(props.selectedIps) && props.selectedIps.join('\n');
    this.state = {
      ...ZoomeyeModal.defaultState,
      ips: ips,
      ipRanges: [],
      ipRangeKeys: [],
      ipRangesMap: {},
      ipRangesSpinning: false,
      selectTemlateLoading: false,
      portTemplates: [],
      portTemplatesMap: {}
    };
  }

  loadIpRanges = () => {
    this.setState({ ipRangesSpinning: true });
    getTargetList({
      page: 1,
      pageSize: 199
    }).then(res => {
      const ipRanges = get(res, 'data.data.list', []);
      const ipRangesMap = ipRanges.reduce((total, current = {}, index) => {
        total[current._id] = index;
        return total;
      }, {});
      const ipRangeKeys = ipRanges.map(i => i._id).filter(i => i);
      this.setState({ ipRanges, ipRangesMap, ipRangeKeys, ipRangesSpinning: false });
    });
  };

  loadPortTemplates = () => {
    this.setState({ selectTemlateLoading: true });
    getAllPortTemplates().then(res => {
      const portTemplates = get(res, 'data.data.list', []);
      const portTemplatesMap = portTemplates.reduce((total, current = {}, index) => {
        total[current._id] = index;
        return total;
      }, {});
      this.setState({ portTemplates, portTemplatesMap, selectTemlateLoading: false });
    });
  };

  // eslint-disable-next-line
  UNSAFE_componentWillReceiveProps(nextProps) {
    const { visible, selectedIps = [] } = nextProps;
    if (!visible) {
      return this.setState(ZoomeyeModal.defaultState);
    } else if (!this.props.visible && selectedIps.length) {
      return this.setState({ ips: selectedIps.join('\n') });
    }
  }

  checkTaskName = () => {
    let taskNameError = '';
    const taskName = this.state.taskName;
    if (!taskName) {
      taskNameError = '任务名不能为空';
    }
    if (taskName.length > 32) {
      taskNameError = '您输入的内容超过32个字符限制';
    }
    if (!NAME_RE.test(taskName)) {
      taskNameError = '您输入的格式有误，仅支持中文、英文、数字、特殊字符 - 、— \\ _ / ：~';
    }
    this.setState({ taskNameError });
    return taskNameError;
  };
  checkMassiveScan() {
    let { ips, ports, mode, portsError, ipsError } = this.state;

    let massiveScanError = '';

    if (!portsError && !ipsError) {
      const ipsCount = getIpsCount(ips.split('\n'));
      const portsCount = getPortsCount(ports.split(','));

      if (portsCount > 1024) {
        if (mode === 'deep') {
          if (ipsCount > 256) {
            massiveScanError = '为了扫描时间考虑，该模式仅开放不超过1个C段的全端口扫描';
          }
        } else if (mode === 'fast') {
          if (ipsCount > 32 * 256) {
            massiveScanError = '为了扫描时间考虑，该模式仅开放不超过32个C段的全端口扫描';
          }
        }
      }
    }

    this.setState({
      massiveScanError
    });

    return massiveScanError;
  }
  checkIps = () => {
    let ipsError = '';
    const { ips, mode } = this.state;
    if (!ips) {
      ipsError = '探测网段不能为空';
    } else {
      const isCorrectFormat = ips
        .split('\n')
        .filter(i => i)
        .every(ip => IP_RE.test(ip) || IP_INTERVAL_RE.test(ip) || CIDR_RE.test(ip));

      if (!isCorrectFormat) {
        ipsError = '探测网段格式不正确';
      }

      const ipsCount = getIpsCount(ips.split('\n'));
      const ipsCountChecker = mode === 'deep' ? MAX_DEEP_DETECTION_COUNT : MAX_FAST_DETECTION_COUNT;
      if (ipsCount > ipsCountChecker) {
        ipsError =
          mode === 'deep'
            ? `该模式下探测目标不超过 ${MAX_DEEP_DETECTION_COUNT} 个 IP`
            : `该模式下探测目标不超过 ${MAX_FAST_DETECTION_COUNT} 个 IP`;
      }
    }

    this.setState({ ipsError }, this.checkMassiveScan);
    return ipsError;
  };
  checkPorts = () => {
    const ports = this.state.ports;
    let portsError = '';
    if (!ports) {
      portsError = '探测端口不能为空';
    } else {
      const isCorrectFormat = ports
        .split(',')
        .every(port => PORT_RE.test(port) || PORT_RANGE_RE.test(port));

      if (!isCorrectFormat) {
        portsError = '探测端口格式不正确';
      }

      if (getPortsCount(ports.split(',')) > MAX_DETECTION_PORT) {
        portsError = `端口个数不能超过${MAX_DETECTION_PORT}`;
      }
    }

    this.setState({ portsError }, this.checkMassiveScan);
    return portsError;
  };

  onCancel = () => this.props.onVisibleChange(false);

  onPortsTypeChange = e => {
    const portsType = e.target.value;
    let commonPort = '21-25,53,80,111,137,139,443,8080';
    let ports = portsType === 'common' ? commonPort : '';
    this.setState(
      {
        ports,
        portsType,
        portsError: '',
        selectedPortTemplate: ''
      },
      this.checkMassiveScan
    );
  };

  onPortsChange = e => {
    const ports = e.target.value;
    this.setState({ ports, portsType: 'custom' }, this.checkPorts);
  };

  onIpsChange = e => {
    const ips = e.target.value;
    this.setState({ ips, ipsType: 'custom' }, this.checkIps);
  };

  onWebFingerChange = value => {
    this.setState({ webFinger: value });
  };

  onNext = () => {
    if ([this.checkIps(), this.checkPorts(), this.checkMassiveScan()].some(i => i)) {
      return;
    }
    const { ips } = this.state;
    const ipsCount = getIpsCount(ips.split('\n'));
    const body = {
      currentTab: 1,
      ipsCount
    };
    if (ipsCount >= 150000) {
      body.packets = 50000;
    } else {
      body.packets = 5000;
    }
    this.setState(body);
  };

  onChangeTab = key => {
    if (key === '1') {
      return this.onNext();
    } else {
      this.setState({ currentTab: 0 });
    }
  };

  onOk = () => {
    if (this.checkTaskName()) {
      return;
    }
    if (!this.props.modules.includes('detection')) {
      return message.info('演示版本不能下发任务，请联系ZoomEye BE团队获取正式版本');
    }
    const {
      mode,
      ipsType,
      ips: ipsStr,
      ports: portsStr,
      cycle,

      webFinger: enable_web_finger,
      packets: speed,
      taskName: name,
      selectedIpRanges,
      runAt
      // urgent
    } = this.state;

    const nowTime = moment();
    const { isRunAt, time } = runAt;
    if ((isRunAt && nowTime > moment(time)) || time === 'Invalid date') {
      return message.warning('您指定的时间有误，请重新选择');
    }

    this.setState({ addingZoomeye: true });
    const body = {
      name: name.replace(/\s/g, ''),
      mode,
      ips: ipsStr.split('\n').filter(i => i),
      ports: portsStr.split(',').filter(i => i),

      enable_web_finger,
      speed,
      runAt
      // urgent
    };
    if (ipsType === 'ipRange') {
      body.ipRangeIds = selectedIpRanges;
    }
    if (cycle) {
      body.duty = {
        // eslint-disable-next-line
        is_duty: true,
        interval: {
          value: cycle,
          unit: 'days'
        }
      };
    }
    addZoomeye(body)
      .then(() => {
        message.success('下发任务成功');
        if (typeof this.props.onSuccess === 'function') {
          this.props.onSuccess();
        }
      })
      .catch(({ type, message: messageString }) => {
        if (type === 'parsed') {
          message.error(messageString);
        } else {
          message.error('下发任务失败');
        }
      })
      .finally(() => {
        this.setState({ addingZoomeye: false });
      });
  };

  onPacketsTypeChange = e => {
    const packetsType = e.target.value;
    const body = { packetsType };
    if (packetsType === 'not-custom') {
      if (this.state.ipsCount >= 150000) {
        body.packets = 50000;
      } else {
        body.packets = 5000;
      }
      this.setState(body);
    } else {
      this.setState(body);
    }
  };

  onModeChange = e => {
    const mode = e.target.value;
    this.setState({ mode }, this.checkIps);
  };

  onPacketsChange = e => {
    let packets = window.parseInt(e.target.value);
    if (isNaN(Number(packets))) {
      return;
    }
    if (packets > 15000000) {
      packets = 15000000;
    }
    this.setState({
      packets,
      packetsType: 'custom'
    });
  };

  onTaskNameChange = e => {
    const taskName = e.target.value;
    this.setState({ taskName }, this.checkTaskName);
  };

  onCycleChange = cycle => {
    this.setState({ cycle });
  };

  onIpsTypeChange = e => {
    const ipsType = e.target.value;
    const body = { ipsType };
    if (ipsType === 'ipRange') {
      this.loadIpRanges();
      body.ipRangesModalVisible = true;
      body.ipsError = '';
    }
    this.setState(body);
  };

  onCheckedIpRange = value => {
    this.setState({
      selectedIpRanges: value
    });
  };

  onSelectedIpRanges = () => {
    const { selectedIpRanges, ipRanges, ipRangesMap } = this.state;
    const ipsArray = selectedIpRanges.reduce((total, ipRangeId) => {
      const currentIps = get(ipRanges, `${ipRangesMap[ipRangeId]}.ips`, []);
      total.push(...currentIps);
      return total;
    }, []);
    const ips = ipsArray.join('\n');
    this.setState(
      {
        ips,
        ipRangesModalVisible: false
      },
      this.checkIps
    );
  };

  clearIps = () => {
    this.setState({
      ips: '',
      ipsError: '',
      massiveScanError: '',
      ipsType: 'custom',
      selectedIpRanges: []
    });
  };

  clearPorts = () => {
    this.setState({
      ports: '',
      portsError: '',
      massiveScanError: '',
      portsType: 'custom',
      selectedPortTemplate: ''
    });
  };

  onPortTemplateChange = value => {
    const { portTemplates, portTemplatesMap } = this.state;
    const ports = get(portTemplates, `${portTemplatesMap[value]}.ports`, []).join(',');
    this.setState(
      {
        selectedPortTemplate: value,
        ports
      },
      this.checkPorts
    );
  };

  onTaskNameKeyUp = e => {
    if (e.keyCode === 13) {
      this.onOk();
    }
  };

  onRunAtChange = runAt => {
    this.setState({ runAt });
  };

  // onUrgentChange = e => {
  //   this.setState({ urgent: e.target.checked });
  // };

  render() {
    const { visible } = this.props;
    const {
      mode,
      currentTab,
      ipsType,
      portsType,
      ips,
      ports,
      cycle,
      // webFinger,
      packets,
      packetsType,
      taskName,
      ipsError,
      portsError,
      massiveScanError,
      taskNameError,
      addingZoomeye,
      ipRanges,
      ipRangesModalVisible,
      ipRangesSpinning,
      portTemplates,
      selectedPortTemplate,
      selectedIpRanges,
      selectTemlateLoading
    } = this.state;

    const footer = [
      <Button onClick={this.onCancel} key="0">
        取消
      </Button>,
      <Button
        onClick={currentTab === 0 ? this.onNext : this.onOk}
        key="1"
        type="primary"
        loading={addingZoomeye}
      >
        {currentTab === 0 ? '下一步' : '确定'}
      </Button>
    ];
    const marks = {
      [cycle]: {
        label: <strong>{cycle}天</strong>
      },
      180: {
        label: <strong>180天</strong>
      }
    };

    const rate = calcZoomeyeRate(packets);

    return (
      <div>
        <Modal
          maskClosable={false}
          className="tm-asset-modal"
          visible={visible}
          title="资产探测"
          footer={footer}
          onCancel={this.onCancel}
          mask={!ipRangesModalVisible}
          destroyOnClose
        >
          <Tabs activeKey={currentTab.toString()} onChange={this.onChangeTab}>
            <TabPane tab="第一步" key="0">
              <div className="step-content">
                <div className={cn('title-wrapper', 'mode-title')}>
                  <span className="item-title">探测模式</span>
                  <RadioGroup className="mode" value={mode} onChange={this.onModeChange}>
                    <Radio value="deep">精准</Radio>
                    <Radio value="fast">极速</Radio>
                  </RadioGroup>
                  <Popover
                    content={
                      <div>
                        出于扫描时间考虑： <br />
                        精准模式建议探测目标不超过{MAX_DEEP_DETECTION_COUNT}个 IP；
                        <br />
                        极速模式建议探测目标不超过{MAX_FAST_DETECTION_COUNT}个 IP；
                        <br />
                        端口数限制：若端口数超过1024，精准模式的探测目标不超过1个C段，极速模式的探测目标不超过32个C段。
                      </div>
                    }
                    overlayStyle={{ width: 380 }}
                  >
                    <Icon type="exclamation-circle" style={{ cursor: 'pointer' }} />
                  </Popover>
                </div>
                <div className={cn('title-wrapper', 'goal-title')}>
                  <span className="item-title">探测目标</span>
                  <RadioGroup className="goal-type" value={ipsType} onChange={this.onIpsTypeChange}>
                    <Radio value="custom">自定义</Radio>
                    <Radio value="ipRange">选择目标组</Radio>
                  </RadioGroup>
                  <span className="clear" onClick={this.clearIps}>
                    <img src={EraserPng} />
                    清空
                  </span>
                </div>
                <div className="ips-wrapper">
                  <TextArea
                    className="ips"
                    value={ips}
                    rows={3}
                    placeholder={ipsInfo}
                    onChange={this.onIpsChange}
                  />
                  {ipsError && <p className="validate-error">{ipsError}</p>}
                  {massiveScanError && <p className="validate-error">{massiveScanError}</p>}
                </div>

                <div className={cn('title-wrapper', 'port-title')}>
                  <span className="item-title">探测端口</span>
                  <RadioGroup
                    className="ports-type"
                    value={portsType}
                    onChange={this.onPortsTypeChange}
                  >
                    <Radio value="common">常用端口</Radio>
                    <Radio value="custom">自定义</Radio>
                    <Radio value="template">策略模板</Radio>
                  </RadioGroup>
                  <span className="clear" onClick={this.clearPorts}>
                    <img src={EraserPng} />
                    清空
                  </span>
                </div>
                <div className="ports-wrapper">
                  {portsType === 'common' ? (
                    <TextArea
                      className="ports"
                      rows={3}
                      value={ports}
                      onChange={this.onPortsChange}
                      placeholder={portsInfo}
                    />
                  ) : portsType === 'custom' ? (
                    <TextArea
                      className="ports"
                      rows={3}
                      value={ports}
                      onChange={this.onPortsChange}
                      placeholder={portsInfo}
                    />
                  ) : (
                    <div className="port-templates">
                      <div className="select-wrapper">
                        <label>选择模板</label>
                        <Select
                          optionLabelProp="title"
                          dropdownClassName="tm-asset-modal-select-drawdown"
                          size="small"
                          value={selectedPortTemplate}
                          onChange={this.onPortTemplateChange}
                          loading={selectTemlateLoading}
                          onFocus={this.loadPortTemplates}
                        >
                          {portTemplates.map(portTemplate => (
                            <Select.Option
                              title={portTemplate.name}
                              value={portTemplate._id}
                              key={portTemplate._id}
                            >
                              <div className="template-item">
                                {portTemplate.name}
                                {selectedPortTemplate === portTemplate._id && <Icon type="check" />}
                              </div>
                            </Select.Option>
                          ))}
                        </Select>
                      </div>
                      <TextArea className="ports" rows={3} value={ports} disabled />
                    </div>
                  )}
                  {portsType === 'template' && (
                    <a href="/asset-config/port-manage" target="_blank">
                      前往进行端口管理
                    </a>
                  )}
                  {portsError && <p className="validate-error">{portsError}</p>}
                </div>
                {/* <div className="wmap-wrapper">
                  <label>
                    Web指纹识别&nbsp;
                    <Tooltip title="开启后将识别Web指纹，请耐心等待">
                      <Icon type="question-circle" />
                    </Tooltip>
                  </label>
                  <Switch
                    className="web-switch"
                    size="small"
                    onChange={this.onWebFingerChange}
                    value={webFinger}
                  />
                </div> */}
                <p className={cn('item-title', 'cycle-info')}>任务周期</p>
                <Slider
                  value={cycle}
                  min={0}
                  max={180}
                  onChange={this.onCycleChange}
                  marks={marks}
                  tipFormatter={value => `${value}天`}
                />
              </div>
            </TabPane>
            <TabPane tab="第二步" key="1">
              <div className="step-content">
                {mode === 'fast' && (
                  <div className="task-packets">
                    <p>已为您的发包率设置为{rate},是否要自定义发包率</p>
                    <RadioGroup value={packetsType} onChange={this.onPacketsTypeChange}>
                      <Radio value="not-custom">否</Radio>
                      <Radio value="custom">是</Radio>
                    </RadioGroup>
                    {packetsType === 'custom' && (
                      <p className="custom-packets">
                        每秒发包
                        {
                          <Input
                            className="packets-count"
                            size="small"
                            value={packets}
                            onChange={this.onPacketsChange}
                          />
                        }
                        个,产生流量{rate}
                      </p>
                    )}
                  </div>
                )}
                <div className="run-at">
                  <RunAtTimePicker onChange={this.onRunAtChange} />
                </div>
                {/* <div className="urgent">
                  <Checkbox onChange={this.onUrgentChange}>
                    加急任务（优先执行，但不影响其它正在执行中的任务）
                  </Checkbox>
                </div> */}
                <div className="task-name">
                  <div className="task-name-title">任务名称</div>
                  <div className="task-name-content">
                    <Input
                      value={taskName}
                      onChange={this.onTaskNameChange}
                      placeholder="请输入中文、英文、特殊字符或数字，不超过32个字符"
                      onKeyUp={this.onTaskNameKeyUp}
                    />
                    {taskNameError && <p className="validate-error">{taskNameError}</p>}
                  </div>
                </div>
              </div>
            </TabPane>
          </Tabs>
        </Modal>
        <Modal
          maskClosable={false}
          title="选择目标组"
          visible={ipRangesModalVisible}
          className={cn('ip-range-select', 'no-header-bottom-lines', 'bottom-center', 'padding-24')}
          onCancel={() => this.setState({ ipsType: 'custom', ipRangesModalVisible: false })}
          onOk={this.onSelectedIpRanges}
        >
          <Spin tip="加载中" spinning={ipRangesSpinning}>
            <CheckboxSelect
              placeholder="请输入关键词搜索"
              onChange={this.onCheckedIpRange}
              options={ipRanges}
              selected={selectedIpRanges}
            />
          </Spin>
          <a className="to-target-manage" href="/target-manage" target="_blank">
            前往进行目标组管理
          </a>
        </Modal>
      </div>
    );
  }
}

ZoomeyeModal.propTypes = {
  visible: PropTypes.bool,
  onVisibleChange: PropTypes.func,
  selectedIps: PropTypes.array,
  onSuccess: PropTypes.func,
  modules: PropTypes.array
};

const mapStateToProps = state => {
  return {
    modules: get(state, 'auth.cert.modules', [])
  };
};

export default connect(mapStateToProps)(ZoomeyeModal);
